package classes;

import java.awt.image.BufferedImage;
import java.util.ArrayList;

/**
 * FindFinderPattern.java
 * 
 * @author Nicole Nelson
 */

/*
 * FindFinderPattern Class
 */
public class FindFinderPattern 
{
	private int BLACK = -16777216;
	private int WHITE = -1;
	private int GREEN = -16711936;
	private int RED = 0xFFFF0000;
	
	//These two guys I want to figure out how to 
	//Calculate these based on the current image
	private int MOE = 10;
	private int LENGTHLIMIT = 10;
	
	
	private BufferedImage altered;
	
	
	/*
	 * 
	 */
	public FinderPattern [] findPattern(BufferedImage image)
	{

		ArrayList<Point> theList = new ArrayList<Point>();
		
		altered = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
		altered.getGraphics().drawImage(image, 0,0, null);
		
		int height = image.getHeight();
		int width = image.getWidth();
		
		int lengthH = 0;
		int lengthV = 0;
		
		//Find the possible points
		for (int y = 0; y < height; y++)
			for (int x = 0; x < width; x++)
			{
				if (image.getRGB(x, y) == BLACK)
				{
					lengthH = findHorizontal(image, x, y);
					if (lengthH > LENGTHLIMIT)
					{
						
						int centerW = x + lengthH / 2;
						int topH = y - lengthH / 2;
						lengthV = findVertical(image, centerW, topH); 

						if (lengthV > LENGTHLIMIT)
						{
							boolean testbool = true;
							int widthErr = lengthH / 9;
							int heightErr = lengthV /9;
							
							for (int i = centerW - widthErr; i < centerW + widthErr && i < image.getWidth(); i++)
								for (int j = y - heightErr; j < y + heightErr && j < image.getHeight(); j++)
									if (image.getRGB(i, j) != BLACK)
										testbool = false;
							if (testbool && x + lengthH < image.getWidth() && image.getRGB(x + lengthH, y) == WHITE 
									&& findHorizontal(image, x + 1, y) > LENGTHLIMIT
									&& findHorizontal(image, x + 2, y) > LENGTHLIMIT
									&& findVertical(image, centerW, topH + 1) > LENGTHLIMIT
									&& findVertical(image, centerW, topH - 1) > LENGTHLIMIT)
							{
								Point p = new Point(x + lengthH / 2, y);
								theList.add(p);
								int z = x;

								for (; z < lengthH + x && z < width; z++)
								{		
									altered.setRGB(z, y, GREEN);
								}
							}
						}
						
					}
					x += lengthH / 7;
				}
			}
		
		return narrowFinders(theList, image);
	}
	
	/*
	 * 
	 */
	private FinderPattern[] narrowFinders(ArrayList<Point> theList, BufferedImage image)
	{
		FinderPattern [] finders = new FinderPattern[3];
		
		
			for (int i = 0; i < theList.size() - 1; i++)
			{
				Point one = (Point) theList.get(i);
				Point two = (Point) theList.get(i + 1);
				if (one.getX() <= two.getX() + MOE && one.getX() >= two.getX() - MOE)
					if (one.getY() <= two.getY() + MOE && one.getY() >= two.getY() - MOE)
					{
						theList.remove(i);
						i--;
					}
			}
		
			for (int i = 0; i < theList.size() - 2; i++)
			{
				Point one = (Point) theList.get(i);
				Point two = (Point) theList.get(i + 2);
				if (one.getX() <= two.getX() + MOE && one.getX() >= two.getX() - MOE)
					if (one.getY() <= two.getY() + MOE && one.getY() >= two.getY() - MOE)
					{
						theList.remove(i);
						i--;
					}
			}
	
		
		ArrayList<Point> theNewList = new ArrayList<Point>();
		
		Point center = new Point();
		
		if (theList.size() >= 3)
		{
			for (int i = 0; i < theList.size(); i++)
			{
				center = (Point) theList.get(i).findCenter(theList.get((i + 1) % theList.size()), theList.get((i + 2) % theList.size()));
				if(center != null)
				{
					theNewList.add((Point) theList.get(i));
					theNewList.add((Point) theList.get((i + 1) % theList.size()));
					theNewList.add((Point) theList.get((i + 2) % theList.size()));
					break;
				}
			}
			
		}
		
		//System.out.println("Actual Points: ");
		for (int i = 0; i < theNewList.size(); i++)
		{
			Point temp = (Point) theNewList.get(i);
			Point [] p = new Point[4];
			//System.out.println("Center: \n\t" + temp.toString());
			Point topLeft = getTopLeft(temp, image);
			altered.setRGB(topLeft.getX(), topLeft.getY(), RED);
			altered.setRGB(topLeft.getX() + 1, topLeft.getY(), RED);
			altered.setRGB(topLeft.getX(), topLeft.getY() + 1, RED);
			altered.setRGB(topLeft.getX() + 1, topLeft.getY() + 1, RED);
			//System.out.println("TopLeft: \n\t" + topLeft.toString());
			p[0] = topLeft;
			Point topRight = getTopRight(temp, image);
			if(topRight.getX() < image.getWidth() && topRight.getY() < image.getHeight())
			{
				altered.setRGB(topRight.getX(), topRight.getY(), RED);
				altered.setRGB(topRight.getX() + 1, topRight.getY(), RED);
				altered.setRGB(topRight.getX(), topRight.getY() + 1, RED);
				altered.setRGB(topRight.getX() + 1, topRight.getY() + 1, RED);
			}
			//System.out.println("TopRight: \n\t" + topRight.toString());
			p[1] = topRight;
			Point bottomLeft = getBottomLeft(temp, image);
			altered.setRGB(bottomLeft.getX(), bottomLeft.getY(), RED);
			altered.setRGB(bottomLeft.getX() + 1, bottomLeft.getY(), RED);
			altered.setRGB(bottomLeft.getX(), bottomLeft.getY() + 1, RED);
			altered.setRGB(bottomLeft.getX() + 1, bottomLeft.getY() + 1, RED);
			//System.out.println("BottomLeft: \n\t" + bottomLeft.toString());
			p[2] = bottomLeft;
			Point bottomRight = getBottomRight(temp, image);
			if(bottomRight.getX() < image.getWidth() && bottomRight.getY() < image.getHeight())
			{
				altered.setRGB(bottomRight.getX(), bottomRight.getY(), RED);
				altered.setRGB(bottomRight.getX() + 1, bottomRight.getY(), RED);
				altered.setRGB(bottomRight.getX(), bottomRight.getY() + 1, RED);
				altered.setRGB(bottomRight.getX() + 1, bottomRight.getY() + 1, RED);
			}
			//System.out.println("BottomRight: \n\t" + bottomRight.toString());
			p[3] = bottomRight;
			altered.setRGB(temp.getX(), temp.getY(), GREEN);
			finders[i] = new FinderPattern(p);
			if(temp == center)
				finders[i].setIsCenter(true);
			else
				finders[i].setIsCenter(false);
//			if (finders[i].getIsCenter())
//				System.out.println("This is the Center Finder");
		}
		return finders;
	}
	

	/*
	 * 
	 */
	private int findHorizontal(BufferedImage findMe, int x, int y)
	{
		int length = 0;
		int counter = 0;
		int temp = 0;
		int startx = x;
		
		//Find Length of Black
		while(x < findMe.getWidth() && findMe.getRGB(x, y) == BLACK)
		{
			counter++;
			x++;
		}
		
		//First set of WHITE
		while(x < findMe.getWidth() && findMe.getRGB(x, y) == WHITE)
		{
			x++;
			temp++;
		}
		if (temp < counter - MOE || temp > counter + MOE)
			return length;
		temp = 0;
		
		//Center Black Section
		while(x < findMe.getWidth() && findMe.getRGB(x, y) == BLACK)
		{
			x++;
			temp++;
		}
		if (temp < 3 * (counter - MOE) || temp > 3 * (counter + MOE))
			return length;
		temp = 0;
		
		//Second set of WHITE
		while(x < findMe.getWidth() && findMe.getRGB(x, y) == WHITE)
		{
			x++;
			temp++;
		}
		if (temp < counter - MOE || temp > counter + MOE)
			return length;
		temp = 0;
		
		//Second set of WHITE
		while(x < findMe.getWidth() && findMe.getRGB(x, y) == BLACK)
		{
			x++;
			temp++;
		}
		if (temp < counter - MOE || temp > counter + MOE && x < findMe.getWidth())
			return length;
		
		length = x - startx;
		
		return length;
	}
	
	/*
	 * 
	 */
	private int findVertical(BufferedImage findMe, int x, int y)
	{
		int length = 0;
		int counter = 0;
		int temp = 0;

		if (y < 0 || x >= findMe.getWidth())
			return length;
			
		//Find Length of Black
		while(y < findMe.getHeight() && findMe.getRGB(x, y) == BLACK)
		{
			counter++;
			y++;
		}
				
		//First set of WHITE
		while(y < findMe.getHeight() && findMe.getRGB(x, y) == WHITE)
		{
			y++;
			temp++;
		}
		if (temp < counter - MOE || temp > counter + MOE)
			return length;
		temp = 0;
		
		//Center Black Section
		while(y < findMe.getHeight() && findMe.getRGB(x, y) == BLACK)
		{
			y++;
			temp++;
		}
		if (temp < 3 * (counter - MOE) || temp > 3 * (counter + MOE))
			return length;
		temp = 0;
		
		//Second set of WHITE
		while(y < findMe.getHeight() && findMe.getRGB(x, y) == WHITE)
		{
			y++;
			temp++;
		}
		if (temp < counter - MOE || temp > counter + MOE)
			return length;
		temp = 0;
		
		//Second set of WHITE
		while(y < findMe.getHeight() && findMe.getRGB(x, y) == BLACK)
		{
			y++;
			temp++;
		}
		if (temp < counter - MOE || temp > counter + MOE && x < findMe.getWidth())
			return length;
		
		length = counter * 7;
		
		return length;
	}

	public Point getTopLeft(Point p, BufferedImage image)
	{
		int tempX = p.getX();
		int tempY = p.getY();
		while(image.getRGB(tempX, tempY) == BLACK)
			tempY--;
		while(image.getRGB(tempX, tempY) == WHITE)
			tempY--;
		while(tempY > 0 && image.getRGB(tempX, tempY) == BLACK)
			tempY--;
		while(tempX > 0 && tempY + 3 < image.getHeight() && (image.getRGB(tempX, tempY + 1) == BLACK || image.getRGB(tempX, tempY + 2) == BLACK || image.getRGB(tempX, tempY + 3) == BLACK))
			tempX--;
		
		Point temp = new Point(tempX, tempY);
		
		return temp;
	}
	
	public Point getTopRight(Point p, BufferedImage image)
	{
		int tempX = p.getX();
		int tempY = p.getY();
		while(image.getRGB(tempX, tempY) == BLACK)
			tempX++;
		while(image.getRGB(tempX, tempY) == WHITE)
			tempX++;
		while(tempX < image.getWidth() && image.getRGB(tempX, tempY) == BLACK)
			tempX++;
		while(tempY > 0 && tempX - 3 > 0 && (image.getRGB(tempX - 1, tempY) == BLACK || image.getRGB(tempX - 2, tempY) == BLACK || image.getRGB(tempX - 3, tempY) == BLACK))
			tempY--;
		
		Point temp = new Point(tempX, tempY);
		
		return temp;
	}
	
	public Point getBottomLeft(Point p, BufferedImage image)
	{
		int tempX = p.getX();
		int tempY = p.getY();
		while(image.getRGB(tempX, tempY) == BLACK)
			tempX--;
		while(image.getRGB(tempX, tempY) == WHITE)
			tempX--;
		while(image.getRGB(tempX, tempY) == BLACK)
			tempX--;
		while(image.getRGB(tempX + 1, tempY) == BLACK || image.getRGB(tempX + 2, tempY) == BLACK || image.getRGB(tempX + 3, tempY) == BLACK)
			tempY++;
		
		Point temp = new Point(tempX, tempY);
		
		return temp;
	}
	
	public Point getBottomRight(Point p, BufferedImage image)
	{
		int tempX = p.getX();
		int tempY = p.getY();
		while(image.getRGB(tempX, tempY) == BLACK)
			tempY++;
		while(image.getRGB(tempX, tempY) == WHITE)
			tempY++;
		while(image.getRGB(tempX, tempY) == BLACK)
			tempY++;
		while(tempX < image.getWidth() && (image.getRGB(tempX, tempY - 1) == BLACK || image.getRGB(tempX, tempY - 2) == BLACK || image.getRGB(tempX, tempY - 3) == BLACK))
			tempX++;
		
		Point temp = new Point(tempX, tempY);
		
		return temp;
	}
	
	/**
	 * THIS IS UGLY CODE!!!!! FIX ME SOON!!!!
	 */
	public FinderPattern[] rotateImage(FinderPattern[] corners, BufferedImage image)
	{
		FinderPattern[] correctCorners = new FinderPattern[3];
		
		
		
		if(corners.length == 3 && corners[0] != null)
		{
			//find center and move that to 0, 0
			int centerIndex = -1;
			
			for (int i = 0; i < corners.length; i++)
				if(corners[i].getIsCenter())
					centerIndex = i;
			
			Point startPoint = new Point();
			int width = 0;
			int height = 0;
			
			
			
			if(corners[centerIndex].getPoint(0).getX() <= corners[(centerIndex + 1) % 3].getPoint(1).getX() &&
					corners[centerIndex].getPoint(0).getY() <= corners[(centerIndex + 1) % 3].getPoint(1).getY() &&
					corners[centerIndex].getPoint(0).getX() <= corners[(centerIndex + 2) % 3].getPoint(2).getX() &&
					corners[centerIndex].getPoint(0).getY() <= corners[(centerIndex + 2) % 3].getPoint(2).getY())
			{
				startPoint = corners[centerIndex].getPoint(0);
				if(startPoint.getY() >= corners[(centerIndex + 1) % 3].getPoint(1).getY() - 5 && startPoint.getY() <= corners[(centerIndex + 1) % 3].getPoint(1).getY() + 5)
				{
					width = corners[(centerIndex + 1) % 3].getPoint(1).getX() - startPoint.getX();
					height = corners[(centerIndex + 2) % 3].getPoint(2).getY() - startPoint.getY();
				}
				else
				{
					width = corners[(centerIndex + 2) % 3].getPoint(1).getX() - startPoint.getX();
					height = corners[(centerIndex + 1) % 3].getPoint(2).getY() - startPoint.getY();
				}
				altered = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
				for (int i = 0; i < width; i++)
					for (int j = 0; j < height; j++)
					{
						//System.out.println(i + " " + j);
						altered.setRGB(i, j, image.getRGB(i + startPoint.getX(), j + startPoint.getY()));
					}
				
			}
			else if(corners[centerIndex].getPoint(3).getX() >= corners[(centerIndex + 1) % 3].getPoint(1).getX() &&
					corners[centerIndex].getPoint(3).getY() >= corners[(centerIndex + 1) % 3].getPoint(1).getY() &&
					corners[centerIndex].getPoint(3).getX() >= corners[(centerIndex + 2) % 3].getPoint(2).getX() &&
					corners[centerIndex].getPoint(3).getY() >= corners[(centerIndex + 2) % 3].getPoint(2).getY())
			{
				startPoint = corners[centerIndex].getPoint(3);
				if(startPoint.getY() >= corners[(centerIndex + 1) % 3].getPoint(2).getY() - 5 && startPoint.getY() <= corners[(centerIndex + 1) % 3].getPoint(2).getY() + 5)
				{
					width = startPoint.getX() - corners[(centerIndex + 1) % 3].getPoint(2).getX();
					height =  startPoint.getY() - corners[(centerIndex + 2) % 3].getPoint(1).getY();
				}
				else
				{
					width = startPoint.getX() - corners[(centerIndex + 2) % 3].getPoint(2).getX(); 
					height = startPoint.getY() - corners[(centerIndex + 1) % 3].getPoint(1).getY();
				}
				altered = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
				//System.out.println(width +  " " + height);
				for (int i = 0; i < width; i++)
					for (int j = 0; j < height; j++)
					{
						//System.out.println(i + " " + j);
						altered.setRGB(i, j, image.getRGB(startPoint.getX() - i, startPoint.getY() - j));
					}
				
			}
			else if(corners[centerIndex].getPoint(1).getX() >= corners[(centerIndex + 1) % 3].getPoint(0).getX() &&
					corners[centerIndex].getPoint(1).getY() <= corners[(centerIndex + 1) % 3].getPoint(0).getY() &&
					corners[centerIndex].getPoint(1).getX() >= corners[(centerIndex + 2) % 3].getPoint(3).getX() &&
					corners[centerIndex].getPoint(1).getY() <= corners[(centerIndex + 2) % 3].getPoint(3).getY())
			{
				startPoint = corners[centerIndex].getPoint(1);
				if(startPoint.getY() >= corners[(centerIndex + 1) % 3].getPoint(0).getY() - 5 && startPoint.getY() <= corners[(centerIndex + 1) % 3].getPoint(0).getY() + 5)
				{
					width = startPoint.getX() - corners[(centerIndex + 1) % 3].getPoint(0).getX();
					height =  corners[(centerIndex + 2) % 3].getPoint(3).getY() - startPoint.getY();
					
				}
				else
				{
					width = startPoint.getX() - corners[(centerIndex + 2) % 3].getPoint(0).getX(); 
					height = corners[(centerIndex + 1) % 3].getPoint(3).getY() - startPoint.getY();
				}
				altered = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
				for (int i = 0; i < width; i++)
					for (int j = 0; j < height; j++)
					{
						altered.setRGB(i, j, image.getRGB(startPoint.getX() - i, j + startPoint.getY()));
					}
				
			}
			else if(corners[centerIndex].getPoint(2).getX() <= corners[(centerIndex + 1) % 3].getPoint(0).getX() &&
					corners[centerIndex].getPoint(2).getY() >= corners[(centerIndex + 1) % 3].getPoint(0).getY() &&
					corners[centerIndex].getPoint(2).getX() <= corners[(centerIndex + 2) % 3].getPoint(3).getX() &&
					corners[centerIndex].getPoint(2).getY() >= corners[(centerIndex + 2) % 3].getPoint(3).getY())
			{
				startPoint = corners[centerIndex].getPoint(2);
				
				if(startPoint.getY() >= corners[(centerIndex + 1) % 3].getPoint(0).getY() - 5 && startPoint.getY() <= corners[(centerIndex + 1) % 3].getPoint(0).getY() + 5)
				{
					width = corners[(centerIndex + 1) % 3].getPoint(0).getX() - startPoint.getX();
					height =  startPoint.getY() - corners[(centerIndex + 2) % 3].getPoint(3).getY();
					
				}
				else
				{
					width = corners[(centerIndex + 1) % 3].getPoint(3).getX() - startPoint.getX(); 
					height = startPoint.getY() - corners[(centerIndex + 2) % 3].getPoint(0).getY();
					System.out.println(width + " " + height);
				}
				

				altered = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
				for (int i = 0; i < width; i++)
					for (int j = 0; j < height; j++)
					{
						altered.setRGB(i, j, image.getRGB(i + startPoint.getX(), startPoint.getY() - j));
					}
				
			}
			else if((corners[centerIndex].getPoint(0).getX() >= corners[(centerIndex + 1) % 3].getPoint(2).getX() &&
					corners[centerIndex].getPoint(0).getY() <= corners[(centerIndex + 1) % 3].getPoint(2).getY() &&
					corners[centerIndex].getPoint(0).getX() <= corners[(centerIndex + 2) % 3].getPoint(1).getX() &&
					corners[centerIndex].getPoint(0).getY() <= corners[(centerIndex + 2) % 3].getPoint(1).getY()) ||
					(corners[centerIndex].getPoint(0).getX() >= corners[(centerIndex + 2) % 3].getPoint(2).getX() &&
					corners[centerIndex].getPoint(0).getY() <= corners[(centerIndex + 2) % 3].getPoint(2).getY() &&
					corners[centerIndex].getPoint(0).getX() <= corners[(centerIndex + 1) % 3].getPoint(1).getX() &&
					corners[centerIndex].getPoint(0).getY() <= corners[(centerIndex + 1) % 3].getPoint(1).getY()))
			{
				startPoint = corners[centerIndex].getPoint(0);
				
			}
	}
		
		return correctCorners;
	}
	
	/*
	 * 
	 */
	public BufferedImage getImage()
	{
		return altered;
	}
	
	
}
